/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package batalhanaval;

import batalhanaval.ambiente.Tabuleiro;
import batalhanaval.componentes.Jogador;
import batalhanaval.componentes.Navio;
import batalhanaval.constantes.Constantes;

/**
 *
 * @author 06070066
 */
public class Jogo {

    private Tabuleiro tabuleiro;
    private int linha;
    private int coluna;
    private Jogador j1,  j2;
    private int contPosicionamento = 0;

    public Jogo(Jogador j1, Jogador j2) {
        this.j1 = j1;
        this.j2 = j2;
        tabuleiro = new Tabuleiro();
    }

    /**
     * metodo responsavel por gerar o tabuleiro do jogo
     * @param linha numero de linhas
     * @param coluna numero de colunas
     * @return retorna uma matriz representando o tabuleiro gerado
     */
    public Navio[][] gerarTabuleiroDoJogo() {
        for (int i = 0; i < getTabuleiro().getTabuleiro().length; i++) {
            for (int j = 0; j < getTabuleiro().getTabuleiro().length; j++) {
                if (numeroTotalDeNavios() < getTabuleiro().getTabuleiro().length) {
                    if (insereAguaOuNavio() != 0) {
                        colocaNavioNoJogo(i, j);
                    }
                } else {
                    break;
                }
            }
        }
        imprimeTabuleiro();
        return getTabuleiro().getTabuleiro();
    }

    public int numeroTotalDeNavios() {
        int numNavios = getJ1().getNavios().size() + getJ2().getNavios().size();
        return numNavios;
    }

    /**
     * metodo que imprime todo tabuleiro
     */
    public void imprimeTabuleiro() {
        for (int i = 0; i < getTabuleiro().getTabuleiro().length; i++) {
            for (int j = 0; j < getTabuleiro().getTabuleiro().length; j++) {
                if (getTabuleiro().getTabuleiro()[i][j] != null) {
                    System.out.println("[" + i + "][" + j + "] = " + getTabuleiro().getTabuleiro()[i][j].saidaNavio());
                }
            }
        }
    }

    /**
     * metodo que insere agua ou navio no tabuleiro
     * @return 0 = agua; 1 = navio
     */
    public int insereAguaOuNavio() {
        return (int) (Math.random() * 2);
    }

    public void atribuiNome_e_tipoNavio(Navio navio, int linha, int coluna) {
        navio.setTipo(decideQualTipoNavio());
        navio.setNome(navio.getTipo() + "-" + linha + coluna);
    }

    /**
     * metodo responsavel por colocar um navio no jogo, ja decidindo qual dos dois jogadores
     * sera o dono do navio. Se o valor de "i" for par o navio ira pertencer ao primeiro
     * jogador, caso contrario ira pertencer ao segundo
     * @param linha valor inteiro que, dependendo se for par ou impar, ira fazer a distribuicao dos navios no jogo
     * @param coluna valor da coluna da matriz
     */
    public void colocaNavioNoJogo(int linha, int coluna) {
        Navio navio = new Navio();
        atribuiNome_e_tipoNavio(navio, linha, coluna);
        insereNaviosNoJogo(navio, linha, coluna);
        if (linha % 2 == 0) {
            getJ1().getNavios().add(navio);
        } else {
            getJ2().getNavios().add(navio);
        }
    }

    /**
     * metodo que decide qual sera o tipo do navio, submarino, cruzador ou caca_minas
     * @return retorna o tipo do navio
     */
    public Constantes.tipo_de_navio decideQualTipoNavio() {
        Constantes.tipo_de_navio tipoNavio = null;
        switch (sorteiaTipoNavio()) {
            case 1:
                tipoNavio = Constantes.tipo_de_navio.SUBMARINO;
                break;
            case 2:
                tipoNavio = Constantes.tipo_de_navio.CRUZADOR;
                break;
            case 3:
                tipoNavio = Constantes.tipo_de_navio.CACA_MINAS;
                break;
        }
        return tipoNavio;
    }

    /**
     * metodo responsavel por sortear o tipo do navio
     * @return retorna um inteiro representando o tipo do navio
     */
    public int sorteiaTipoNavio() {
        return (int) (Math.random() * 3) + 1;
    }

    /**
     * metodo que verifica se a posicao do navio nao esta ocupada. Caso esteje ele verifica
     * qual o tipo do navio, se for um submarino ele guarda a referencia daquele
     * navio na posicao sorteada e vai para a proxima iteracao do laco, caso contrario
     * ele guarda a referencia daquele navio e calcula qual sera o posicionamento do navio
     */
    public void insereNaviosNoJogo(Navio navio, int linha, int coluna) {
        if (!verificaPosicaoOcupada(linha, coluna)) {
            contPosicionamento = 0;
            if (navio.getTipo() != Constantes.tipo_de_navio.SUBMARINO) {
                getTabuleiro().getTabuleiro()[linha][coluna] = navio;
                calculaPosicionamento(linha, coluna, navio);
            } else {
                colocarSubmarino(linha, coluna, navio);
            }
        }
    }

    /**
     *metodo que coloca um submarino em uma posicao da matriz
     * @param linha valor da linha da matriz
     * @param coluna valor da coluna da matriz
     * @param navio possui a referencia do navio
     */
    public void colocarSubmarino(int linha, int coluna, Navio navio) {
        atribuiNome_e_tipoNavio(navio, linha, coluna);
        getTabuleiro().getTabuleiro()[linha][coluna] = navio;
    }

    /**
     * matodo que verifica se uma dada posicao esta ocupada
     * @param linha valor da linha da matriz
     * @param coluna valor da coluna da matriz
     * @return true se a posicao estiver ocupada
     */
    public boolean verificaPosicaoOcupada(int linha, int coluna) {
        boolean posicaoOcupada = false;
        if (getTabuleiro().getTabuleiro()[linha][coluna] != null) {
            posicaoOcupada = true;
        }
        return posicaoOcupada;
    }

    /**
     * metodo que coloca um cruzador em uma posicao da matriz
     * @param linha valor da linha da matriz
     * @param coluna valor da coluna da matriz
     * @param navio contem a referencia do navio
     * @param posicionamento posicionamento que o navio devera posuir
     */
    public boolean colocaCruzador(int linha, int coluna, Navio navio, Constantes.posicionamento posicionamento) {
        boolean inseriuNavio = false;
        if (posicionamento.getPosicionamento() == 1) {
            if (!ultrapassaLimiteMatriz(linha, coluna, navio, posicionamento)) {
                if (!verificaPosicaoOcupada(linha - 1, coluna)) {
                    getTabuleiro().getTabuleiro()[linha - 1][coluna] = navio;
                    inseriuNavio = true;
                } else {
//                    System.out.println("posicao [" + (linha - 1) + "][" + coluna + "] ocupada entao vira submarino na [" + linha + "][" + coluna + "]");
                    colocarSubmarino(linha, coluna, navio);
                    inseriuNavio = true;
                }
            } else {
                return inseriuNavio;
            }
        } else if (posicionamento.getPosicionamento() == 2) {
            if (!ultrapassaLimiteMatriz(linha, coluna, navio, posicionamento)) {
                if (!verificaPosicaoOcupada(linha, coluna + 1)) {
                    getTabuleiro().getTabuleiro()[linha][coluna + 1] = navio;
                    inseriuNavio = true;
                } else {
//                    System.out.println("posicao [" + (linha) + "][" + (coluna + 1) + "] ocupada entao vira submarino na [" + linha + "][" + coluna + "]");
                    colocarSubmarino(linha, coluna, navio);
                    inseriuNavio = true;
                }
            } else {
                return inseriuNavio;
            }
        } else if (posicionamento.getPosicionamento() == 3) {
            if (!ultrapassaLimiteMatriz(linha, coluna, navio, posicionamento)) {
                if (!verificaPosicaoOcupada(linha + 1, coluna)) {
                    getTabuleiro().getTabuleiro()[linha + 1][coluna] = navio;
                    inseriuNavio = true;
                } else {
//                    System.out.println("posicao [" + (linha + 1) + "][" + coluna + "] ocupada entao vira submarino na [" + linha + "][" + coluna + "]");
                    colocarSubmarino(linha, coluna, navio);
                    inseriuNavio = true;
                }
            } else {
                return inseriuNavio;
            }
        } else if (posicionamento.getPosicionamento() == 4) {
            if (!ultrapassaLimiteMatriz(linha, coluna, navio, posicionamento)) {
                if (!verificaPosicaoOcupada(linha, coluna - 1)) {
                    getTabuleiro().getTabuleiro()[linha][coluna - 1] = navio;
                    inseriuNavio = true;
                } else {
//                    System.out.println("posicao [" + (linha) + "][" + (coluna - 1) + "] ocupada entao vira submarino na [" + linha + "][" + coluna + "]");
                    colocarSubmarino(linha, coluna, navio);
                    inseriuNavio = true;
                }
            } else {
                return inseriuNavio;
            }
        }
        return inseriuNavio;
    }

    /**
     * metodo que verifica se uma dada posicao ultrapassa o limite da matriz
     * @param linha valor da linha da matriz
     * @param coluna valor da coluna da matriz
     * @param navio contem a referencia do navio
     * @return true se a posicao ultrapassar o limite da matriz
     */
    public boolean ultrapassaLimiteMatriz(int linha, int coluna, Navio navio, Constantes.posicionamento posicionamento) {
        boolean ultrapassouMatriz = false;
        if (posicionamento.getPosicionamento() == Constantes.posicionamento.NORTE.getPosicionamento()) {
            if ((linha + 1) - navio.getTipo().getNumeros_de_posicoes() < 0) {
                ultrapassouMatriz = true;
            }
        } else if (posicionamento.getPosicionamento() == Constantes.posicionamento.LESTE.getPosicionamento()) {
            if (navio.getTipo().getNumeros_de_posicoes() + linha > getTabuleiro().getTabuleiro().length) {
                ultrapassouMatriz = true;
            }
        } else if (posicionamento.getPosicionamento() == Constantes.posicionamento.SUL.getPosicionamento()) {
            if (navio.getTipo().getNumeros_de_posicoes() + coluna > getTabuleiro().getTabuleiro().length) {
                ultrapassouMatriz = true;
            }
        } else if ((coluna + 1) - navio.getTipo().getNumeros_de_posicoes() < 0) {
            ultrapassouMatriz = true;
        }
        return ultrapassouMatriz;

    }

    /**
     * metodo que coloca um caca minas em uma posicao da matriz
     * @param linha valor da linha da matriz
     * @param coluna valor da coluna da matriz
     * @param navio contem a referencia do navio
     * @param posicionamento posicionamento que o navio devera posuir
     */
    public boolean colocarCacaMinas(int linha, int coluna, Navio navio, Constantes.posicionamento posicionamento) {
        boolean inseriuNavio = false;
        if (posicionamento.getPosicionamento() == 1) {
            if (!ultrapassaLimiteMatriz(linha, coluna, navio, posicionamento)) {
                if (!verificaPosicaoOcupada(linha - 1, coluna) && !verificaPosicaoOcupada(linha - 2, coluna)) {
                    getTabuleiro().getTabuleiro()[linha - 1][coluna] = navio;
                    getTabuleiro().getTabuleiro()[linha - 2][coluna] = navio;
                    inseriuNavio = true;
                } else {
//                    System.out.println("posicao [" + (linha - 1) + "][" + (coluna) + "] e [" + (linha - 2) + "][" + coluna + "] estao ocupadas, entao vira submarino na [" + linha + "][" + coluna + "]");
                    colocarSubmarino(linha, coluna, navio);
                    inseriuNavio = true;
                }
            } else {
                return inseriuNavio;
            }
        } else if (posicionamento.getPosicionamento() == 2) {
            if (!ultrapassaLimiteMatriz(linha, coluna, navio, posicionamento)) {
                if (!verificaPosicaoOcupada(linha, coluna + 1) && !verificaPosicaoOcupada(linha, coluna + 2)) {
                    getTabuleiro().getTabuleiro()[linha][coluna + 1] = navio;
                    getTabuleiro().getTabuleiro()[linha][coluna + 2] = navio;
                    inseriuNavio = true;
                } else {
//                    System.out.println("posicao [" + (linha) + "][" + (coluna + 1) + "] e [" + linha + "][" + (coluna + 2) + "] estao ocupadas, entao vira submarino na [" + linha + "][" + coluna + "]");
                    colocarSubmarino(linha, coluna, navio);
                    inseriuNavio = true;
                }
            } else {
                return inseriuNavio;
            }
        } else if (posicionamento.getPosicionamento() == 3) {
            if (!ultrapassaLimiteMatriz(linha, coluna, navio, posicionamento)) {
                if (!verificaPosicaoOcupada(linha + 1, coluna) && !verificaPosicaoOcupada(linha + 2, coluna)) {
                    getTabuleiro().getTabuleiro()[linha + 1][coluna] = navio;
                    getTabuleiro().getTabuleiro()[linha + 2][coluna] = navio;
                    inseriuNavio = true;
                } else {
//                    System.out.println("posicao [" + (linha + 1) + "][" + (coluna) + "] e [" + (linha + 2) + "][" + coluna + "] estao ocupadas, entao vira submarino na [" + linha + "][" + coluna + "]");
                    colocarSubmarino(linha, coluna, navio);
                    inseriuNavio = true;
                }
            } else {
                return inseriuNavio;
            }
        } else if (posicionamento.getPosicionamento() == 4) {
            if (!ultrapassaLimiteMatriz(linha, coluna, navio, posicionamento)) {
                if (!verificaPosicaoOcupada(linha, coluna - 1) && !verificaPosicaoOcupada(linha, coluna - 2)) {
                    getTabuleiro().getTabuleiro()[linha][coluna - 1] = navio;
                    getTabuleiro().getTabuleiro()[linha][coluna - 2] = navio;
                    inseriuNavio = true;
                } else {
//                    System.out.println("posicao [" + (linha) + "][" + (coluna - 1) + "] e [" + linha + "][" + (coluna - 2) + "] estao ocupadas, entao vira submarino na [" + linha + "][" + coluna + "]");
                    colocarSubmarino(linha, coluna, navio);
                    inseriuNavio = true;
                }
            } else {
                return inseriuNavio;
            }
        }
        return inseriuNavio;
    }

    /**
     * metodo que calcula qual devera ser o posicionamento da matriz
     * @param posicionamento posicionamento que o navio devera ter
     * @param linha valor da linha da matriz
     * @param coluna valor da coluna da matriz
     * @param navio contem a referencia do navio
     */
    public void calculaPosicionamento(int linha, int coluna, Navio navio) {
        boolean inseriuNavio = false;
        for (Constantes.posicionamento posicionamento : Constantes.posicionamento.values()) {
            contPosicionamento++;
            if (contPosicionamento <= 4) {
                if (navio.getTipo().getNumeros_de_posicoes() < Constantes.tipo_de_navio.CACA_MINAS.getNumeros_de_posicoes()) {
                    inseriuNavio = colocaCruzador(linha, coluna, navio, posicionamento);
                } else {
                    inseriuNavio = colocarCacaMinas(linha, coluna, navio, posicionamento);
                }
            } else {
                colocarSubmarino(linha, coluna, navio);
            }
            if (inseriuNavio) {
                break;
            }
        }
    }

    /**
     * define o tamanho do navio, se ele vai ser um cruzador(duas posicoes) ou
     * um caca minas(tres posicoes)
     * @return inteiro representando quantas casas um navio devera ter alem das que ja possui
     */
    public int defineTamanhoDoNavio() {
        int numPosicoes = (int) (Math.random() * 2) + 1;
        return numPosicoes;
    }

    /**
     * metodo que realiza o sorteio de uma linha ou coluna
     * @return inteiro sorteado
     */
    public int sorteiaPosicao() {
        return (int) (Math.random() * Constantes.getQUANTIDADE_DE_OBJETOS());
    }

    /**
     * @return the tabuleiro
     */
    public Tabuleiro getTabuleiro() {
        return tabuleiro;
    }

    /**
     * @param tabuleiro the tabuleiro to set
     */
    public void setTabuleiro(Tabuleiro tabuleiro) {
        this.tabuleiro = tabuleiro;
    }

    /**
     * @return the j1
     */
    public Jogador getJ1() {
        return j1;
    }

    /**
     * @param j1 the j1 to set
     */
    public void setJ1(Jogador j1) {
        this.j1 = j1;
    }

    /**
     * @return the j2
     */
    public Jogador getJ2() {
        return j2;
    }

    /**
     * @param j2 the j2 to set
     */
    public void setJ2(Jogador j2) {
        this.j2 = j2;
    }
}
